// Copyright 2022 jeff.li. and/or its affiliates.

#include <tbir/runtime/native_func_maker.h>

#include <tbir/runtime/container/native_func_private.h>
#include <tbir/runtime/container/user_data_interface.h>
#include <tbir/runtime/container/user_data_private.h>
#include <tbir/runtime/container/user_data_ref.h>
#include <tbir/runtime/py_args.h>
#include <tbir/runtime/registry.h>
#include <tbir/runtime/runtime_value.h>

namespace tbir::runtime {

    namespace {
        void *creater(void *data) {
            return new(data) NativeFuncUserData();
        }

        void deleter(ILightUserData *data) {
            ((NativeFuncUserData *) (data))->~NativeFuncUserData();
        }
    }  // namespace

    TURBO_EXPORT UserDataRef make_native_function(string_view func_name) {
        auto native_function_register = FunctionRegistry::Get(func_name);
        MXCHECK(native_function_register != nullptr) << "Native Function not found: " << func_name;
        auto ret = UserDataRef(0, 0, sizeof(NativeFuncUserData), creater, deleter, nullptr);
        ((NativeFuncUserData *) (ret->ud_ptr))->__call__ = native_function_register;
        return ret;
    }

    TURBO_EXPORT RTValue call_native_function(string_view func_name, PyArgs args) {
        auto native_function_register = FunctionRegistry::Get(func_name);
        MXCHECK(native_function_register != nullptr) << "Native Function not found: " << func_name;
        return (*native_function_register)(args);
    }

    TBIR_REGISTER_GLOBAL("native.call_native_function").set_body([](PyArgs args) -> RTValue {
        MXCHECK(args.size() >= 1);
        auto function_name = args[0].As<string_view>();
        return call_native_function(function_name, PyArgs(args.begin() + 1, args.size() - 1));
    });

}  // namespace tbir::runtime